﻿using NetTopologySuite.Algorithm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ZhonTai.Admin.Core.Attributes;
using ZhonTai.Admin.Core.Consts;
using ZhonTai.Admin.Core.Dto;
using ZhonTai.Admin.Domain.Patrol;
using ZhonTai.Admin.Repositories.Patrol;
using ZhonTai.Admin.Services.Patrol.Dto;
using ZhonTai.Admin.Services.Patrol.TaskDto;
using ZhonTai.DynamicApi;
using ZhonTai.DynamicApi.Attributes;

namespace ZhonTai.Admin.Services.Patrol
{
    /// <summary>
    /// 任务调度服务
    /// </summary>
    [Order(12)]
    [DynamicApi(Area = AdminConsts.AreaName)]
    public class ScheduleTaskService:  BaseService, IScheduleTaskService, IDynamicApi
    {
        private IPatrolTaskRepository _taskRepository => LazyGetRequiredService<IPatrolTaskRepository>();
        private IPatrolTaskConfigRepository _taskConfigRepository => LazyGetRequiredService<IPatrolTaskConfigRepository>();

        private IPatrolTaskProcessInfoRepository _taskProcessInfoRepo => LazyGetRequiredService<IPatrolTaskProcessInfoRepository>();

        private IPatrolTaskNodeRepository _taskNodeRepository => LazyGetRequiredService<IPatrolTaskNodeRepository>();

        private IPatrolTaskNodeItemRepository _taskNodeItemRepository => LazyGetRequiredService<IPatrolTaskNodeItemRepository>();


        public ScheduleTaskService() { }

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<long> AddAsync(PatrolTaskAddInput input)
        {
            var entity = Mapper.Map<PatrolTaskEntity>(input);
            var item = await _taskRepository.InsertAsync(entity);
            return item?.Id ?? 0;
        }

        /// <summary>
        /// 任务配置
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<bool> SetConfigAsync(PatrolTaskConfigInputs input)
        {
            var entities = Mapper.Map<ICollection<PatrolTaskConfigEntity>>(input.Configs);
            foreach (var entity in entities)
            {
                entity.TaskId = input.TaskId;
            }
            var result = await _taskConfigRepository.InsertAsync(entities);
            return result?.Count > 0;
        }

        /// <summary>
        /// 查询任务列表
        /// 移动端
        /// </summary>
        /// <returns></returns>
        public async Task<IList<PatrolTaskPageOutput>> GetPageAsync(PageInput<PatrolTaskGetPageDto> input)
        {
            ////1.查询所有和当前用户相关的任务配置和任务
            //var taskConfigs =await _taskConfigRepository.Select
            //    .Where(o => o.Users.Contains(User.Id))
            //    .Include(o=>o.Task)
            //    .ToListAsync();
            
            //1.获取所有包含当前人员的配置任务
            var tasks =  await _taskRepository.Select
                .IncludeMany(o => o.Configs, then => then.Where(o => o.Users.Contains(User.Id)))
                .ToListAsync<PatrolTaskPageOutput>();
            //2.获取所有包含的任务
            var result =  tasks.Where(o => o.Configs != null || o.Configs.Count() == 0).ToList();
            
            return result;
        }

        /// <summary>
        /// 获取任务所有详情()
        /// 当前任务下的配置，配置表单以及表单的项
        /// </summary>
        /// <param name="id">任务ID</param>
        /// <returns></returns>
        public async Task<PatrolTaskOutput> GetDetailAsync(long id)
        {
            if(id== 0)
                throw new ArgumentNullException(nameof(id));
            var result = await _taskRepository.Select.Where(o => o.Id == id)
                .IncludeMany(o => o.Configs, then => then.IncludeMany(a => a.Form.Controls))
                .ToOneAsync<PatrolTaskOutput>();
            return result;
        }

        /// <summary>
        /// 开始执行任务
        /// 移动端点击开始
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<long> StartTaskAsync(long id)
        {
            if (id == 0)
                throw new ArgumentNullException(nameof(id));
            
            //1.判断当前任务是否已经执行
            var taskProcess = await _taskProcessInfoRepo.Select.Where(o => o.TaskId == id && o.UserId == User.Id).ToOneAsync();
            if(taskProcess!=null)
                return taskProcess.Id;
            //2.不存在，新增
            var result =await _taskProcessInfoRepo.InsertAsync(new PatrolTaskProcessInfoEntity { 
                TaskId = id,
                UserId = User.Id
            });
            return result.Id;
        }

        /// <summary>
        /// 任务结束
        /// </summary>
        /// <returns></returns>
        public async Task<bool> EndTaskAsync(PatrolTaskProcessDto dto)
        {
            //更新
            var taskProcess = await _taskProcessInfoRepo.Where(o => o.Id == dto.Id).ToOneAsync();
            if(taskProcess==null) throw new Exception("当前任务还未开始执行");

            taskProcess.Mileage = dto.Mileage;
            taskProcess.Duration = dto.Duration;

            int count = await _taskProcessInfoRepo.UpdateAsync(taskProcess);
            return count > 0;
        }

        /// <summary>
        /// 上传事件点
        /// </summary>
        /// <returns></returns>
        [AdminTransaction]
        public async Task<long> UploadNodeAsync(PatrolTaskNodeDto dto)
        {
            if (dto == null)
                throw new ArgumentNullException(nameof(dto));

            var entity = Mapper.Map<PatrolTaskNodeEntity>(dto);

            //存储
            var result = await _taskNodeRepository.InsertAsync(entity);

            dto.Items.ToList().ForEach(async o =>
            {
                if (o.Value != null)
                {
                    PatrolTaskNodeItemEntity item = new PatrolTaskNodeItemEntity()
                    {
                        TaskId = result.TaskId,
                        UserId = result.UserId,
                        TaskConfigId = result.TaskConfigId,
                        TaskProcessId = result.TaskProcessId,
                        KeyName = o.Key
                    };
                    item.FillKVToMe(o);
                    await _taskNodeItemRepository.InsertAsync(item);
                }
            });
            return result.Id;
        }
    }
}
